package com.zzyl.nursing.ws;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.nursing.domain.vo.AlertNotifyVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.config.annotation.EnableWebSocket;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@EnableWebSocket
@ServerEndpoint("/ws/{sid}") // ws的连接地址
public class WebSocketServer {
    
    // 用户的连接
    private static final ConcurrentHashMap<String, Session> sessionMap=new ConcurrentHashMap<>();
    
    /**
     * 连接建立时触发
     * @param session
     * @param sid
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("sid") String sid) {
        log.info("有客户端连接到了服务器 , {}",sid);
        sessionMap.put(sid,session);
    }
    
    /**
     * 服务端接收到消息时触发
     * @param session
     * @param message
     * @param sid
     */
    @OnMessage
    public void onMessage(Session session,String message,@PathParam("sid") String sid) {
        log.info("接收到了客户端 {} 发来的消息 : {}",sid,message);
        sendMessageToAll(message);
    }
    
    /**
     * 连接关闭时触发
     * @param session
     * @param sid
     */
    @OnClose
    public void onClose(Session session,@PathParam("sid") String sid) {
        log.info("与客户端{}，断开连接",sid);
        sessionMap.remove(sid);
    }
    
    /**
     * 通信发生错误时触发
     * @param session
     * @param sid
     * @param throwable
     */
    @OnError
    public void onError(Session session,@PathParam("sid") String sid,Throwable throwable) {
        log.info("与客户端{}，连接出现错误",sid);
        throwable.printStackTrace();
    }
    
    /**
     * 广播消息
     * @param message
     * @throws IOException
     */
    @SneakyThrows
    public void sendMessageToAll(String message) {
        Collection<Session> sessions=sessionMap.values();
        if (!CollUtil.isEmpty(sessions)) {
            for (Session session : sessions) {
                // 服务器向客户端发送消息
                session.getBasicRemote()
                       .sendText(message);
            }
        }
    }
    
    /**
     * 发送websocket消息给指定消费者
     * @param alertNotifyDto 报警消息
     * @param userIds        报警数据map
     * @throws IOException io异常
     */
    public void sendMessageToConsumer(AlertNotifyVo alertNotifyVo,List<Long> userIds) {
        // 如果消费者为空，程序结束
        if (CollUtil.isEmpty(userIds)) {
            return;
        }
        
        // 如果websoket客户端为空，程序结束
        if (ObjectUtil.isEmpty(sessionMap)) {
            return;
        }
        
        // 遍历消费者，发送消息
        // key为消息接收人id，value为报警数据id
        userIds.forEach(userId -> {
            // 获取该消费者的websocket连接，如果不存在，跳出本次循环
            Session session=sessionMap.get(String.valueOf(userId));
            if (ObjectUtil.isEmpty(session)) {
                // 通过其它手段通知人员，对接第三方接口
                return;
            }
            // 获取该消费者的websocket连接，并发送消息
            try {
                session.getBasicRemote()
                       .sendText(JSONUtil.toJsonStr(alertNotifyVo));
            } catch (IOException e) {
                throw new BaseException("websocket推送消息失败");
            }
        });
    }
}